package com.ives.lock;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

import java.net.InetAddress;
import java.util.Objects;

/**
 * @author 陈玉林
 * @desc TODO
 * @date 2020/6/28 9:42
 */
public class RedisLock {
    private String lockKey;
    private static final int EXPIRE_TIME = 30;
    private static final String SUCCESS = "OK";
    private static JedisPool jedisPool = new JedisPool();

    public RedisLock(String lockKey) {
        this.lockKey = lockKey;
    }

    public boolean lock() {
        SetParams setParams = new SetParams().nx().ex(EXPIRE_TIME);
        final String lockVal = getLockValue();
        final Jedis jedis = jedisPool.getResource();
        final String lockResult = jedis.set(lockKey, lockVal, setParams);
        jedis.close();
        boolean result = Objects.nonNull(lockResult) && SUCCESS.equals(lockResult);
        if (result) {
            GuardThread guardThread = new GuardThread(lockKey, lockVal);
            guardThread.setDaemon(true);
            guardThread.start();
        }
        return result;
    }

    /**
     * 使用主机ip+线程id作为锁的内容，在锁续命时判断
     * @return String
     */
    private String getLockValue() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            return addr.getHostAddress() + Thread.currentThread().getId();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private class GuardThread extends Thread {
        private String key;
        private String lockVal;

        public GuardThread(String key, String lockVal) {
            super("GuardThread");
            this.key = key;
            this.lockVal = lockVal;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    //间隔1s检测一次，节约cpu资源
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                final Jedis jedis = jedisPool.getResource();
                String lockVal = jedis.get(key);
                if (this.lockVal.equals(lockVal)) {
                    final Long ttl = jedis.ttl(key);
                    System.out.println(String.format("线程【%s】持有锁剩余时间：%s", lockVal, ttl));
                    //锁寿命小于10s进行续命
                    if (ttl < 10) {
                        jedis.expire(key, EXPIRE_TIME);
                        System.out.println(String.format("线程【%s】续期后剩余时间：%s", lockVal, jedis.ttl(key)));
                    }
                }
                jedis.close();
            }
        }
    }


    public void unLock() {
        final Jedis jedis = jedisPool.getResource();
        jedis.del(lockKey);
        jedis.close();
    }

}
